#include <X11/Xatom.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <freetype2/ft2build.h>
#include FT_FREETYPE_H
#include <ctype.h>
#include <limits.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
typedef struct {
  char file_path[1024];
  char url[1024];
  char geometry[32];
  bool keep_cache;
} Config;

typedef struct {
  int x, y, w, h;
  const char *label;
  bool hovered;
  bool pressed;
} Button;

typedef struct {
  int x, y, w, h;
  char *text;
  int max_len;
  bool focused;
  const char *label;
} InputBox;

static Display *dpy;
static Window win;
static GC gc;
static FT_Library ft_lib;
static FT_Face ft_face;
static Config cfg;
static Button btn_browse, btn_play, btn_clean, btn_help;
static InputBox input_file, input_url, input_geometry;
static bool show_help = false;
static const char *help_text =
    "Usage:\n"
    "  - Select local file or enter URL (choose one)\n"
    "  - Window geometry: widthxheight+X+Y (default 1920x1080+0+0)\n"
    "  - Keep cache: Reuse cache for same URL\n"
    "  - Clean cache: Delete all cached files\n"
    "  - Press ESC to close help";

int init_freetype() {
  if (FT_Init_FreeType(&ft_lib) != 0) {
    fprintf(stderr, "FreeType init failed\n");
    return -1;
  }

  const char *font_paths[] = {
      "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", // 优先可靠字体
      "/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf",
      "/usr/share/fonts/truetype/ubuntu/Ubuntu-R.ttf",
      "/usr/share/fonts/truetype/fonts-dejavu/DejaVuSans.ttf"};

  for (size_t i = 0; i < sizeof(font_paths) / sizeof(font_paths[0]); i++) {
    if (FT_New_Face(ft_lib, font_paths[i], 0, &ft_face) == 0) {
      if (FT_Set_Pixel_Sizes(ft_face, 0, 16) == 0) { // 检查字体大小设置
        return 0;
      }
      FT_Done_Face(ft_face); // 失败则释放当前face
    }
  }

  fprintf(stderr, "No suitable font found\n");
  FT_Done_FreeType(ft_lib);
  return -1;
}

void init_gui() {
  memset(cfg.file_path, 0, 1024);
  memset(cfg.url, 0, 1024);
  strcpy(cfg.geometry, "1920x1080+0+0");
  cfg.keep_cache = false;

  input_file =
      (InputBox){50, 80, 400, 30, cfg.file_path, 1023, false, "Local File:"};
  input_url = (InputBox){50, 140, 400, 30, cfg.url, 1023, false, "URL:"};
  input_geometry =
      (InputBox){50, 200, 200, 30, cfg.geometry, 31, false, "Window Geometry:"};

  btn_browse = (Button){470, 80, 80, 30, "Browse...", false, false};
  btn_play = (Button){50, 320, 120, 40, "Play", false, false};
  btn_clean = (Button){200, 320, 120, 40, "Clean Cache", false, false};
  btn_help = (Button){350, 320, 120, 40, "Help", false, false};
}

void draw_text(int x, int y, const char *text, unsigned long color) {
  if (!text || !*text || !ft_face)
    return; // 空文本或无字体直接返回

  XSetForeground(dpy, gc, color);
  FT_GlyphSlot slot = ft_face->glyph;
  int pen_x = x, pen_y = y;

  for (size_t i = 0; text[i] != '\0'; i++) {
    // 严格检查字符加载结果，失败则跳过
    if (FT_Load_Char(ft_face, text[i], FT_LOAD_RENDER) != 0) {
      continue;
    }

    // 确保位图缓冲区有效
    if (slot->bitmap.buffer == NULL) {
      continue;
    }

    // 创建XImage，严格指定参数
    XImage *img = XCreateImage(dpy, DefaultVisual(dpy, DefaultScreen(dpy)), 8,
                               ZPixmap, 0, (char *)slot->bitmap.buffer,
                               slot->bitmap.width, slot->bitmap.rows, 8, 0);

    if (img) {
      // 绘制前检查坐标有效性
      int draw_x = pen_x + slot->bitmap_left;
      int draw_y = pen_y - slot->bitmap_top;
      if (draw_x >= 0 && draw_y >= 0) {
        XPutImage(dpy, win, gc, img, 0, 0, draw_x, draw_y, slot->bitmap.width,
                  slot->bitmap.rows);
      }
      XDestroyImage(img); // 立即销毁，避免内存泄漏
    }

    // 更新画笔位置（FreeType的advance单位是1/64像素）
    pen_x += slot->advance.x >> 6;
    pen_y += slot->advance.y >> 6;
  }
}

unsigned int get_text_width(const char *text) {
  if (!text || !*text || !ft_face)
    return 0;

  unsigned int width = 0;
  FT_GlyphSlot slot = ft_face->glyph;

  for (size_t i = 0; text[i] != '\0'; i++) {
    if (FT_Load_Char(ft_face, text[i], FT_LOAD_RENDER) != 0) {
      continue;
    }
    width += slot->advance.x >> 6;
  }
  return width;
}

void draw_rect(int x, int y, int w, int h, unsigned long color) {
  XSetForeground(dpy, gc, color);
  XFillRectangle(dpy, win, gc, x, y, w, h);
}

void draw_rect_border(int x, int y, int w, int h, unsigned long color) {
  XSetForeground(dpy, gc, color);
  XDrawRectangle(dpy, win, gc, x, y, w, h);
}

void draw_input_box(InputBox *box) {
  unsigned long border = box->focused ? 0xFF0000 : 0x000000;
  draw_rect(box->x, box->y, box->w, box->h, 0xFFFFFF);
  draw_rect_border(box->x, box->y, box->w, box->h, border);
  draw_text(box->x, box->y - 5, box->label, 0x000000);
  draw_text(box->x + 5, box->y + 20, box->text, 0x000000);

  if (box->focused) {
    unsigned int len = get_text_width(box->text);
    XSetForeground(dpy, gc, 0x000000);
    XDrawLine(dpy, win, gc, box->x + 5 + len, box->y + 5, box->x + 5 + len,
              box->y + 25);
  }
}

void draw_button(Button *btn) {
  unsigned long bg = 0xFFFFFF;
  if (btn->pressed)
    bg = 0x888888;
  else if (btn->hovered)
    bg = 0xEEEEEE;

  draw_rect(btn->x, btn->y, btn->w, btn->h, bg);
  draw_rect_border(btn->x, btn->y, btn->w, btn->h, 0x000000);

  unsigned int len = get_text_width(btn->label);
  int tx = btn->x + (btn->w - len) / 2;
  int ty = btn->y + (btn->h + 8) / 2;
  draw_text(tx, ty, btn->label, 0x000000);
}

void handle_input(InputBox *box, XEvent *ev) {
  if (!box->focused || ev->type != KeyPress)
    return;

  KeySym ks;
  char buf[16];
  int len = XLookupString(&ev->xkey, buf, sizeof(buf) - 1, &ks, NULL);
  buf[len] = '\0';

  if (ks == XK_BackSpace && strlen(box->text) > 0) {
    box->text[strlen(box->text) - 1] = '\0';
  } else if (isprint((unsigned char)buf[0]) &&
             strlen(box->text) < box->max_len) {
    size_t current_len = strlen(box->text);
    if (current_len + len < box->max_len) {
      strncat(box->text, buf, len);
    }
  }
}

void open_file_dialog() {
  FILE *pipe =
      popen("zenity --file-selection --title='Select Video File'", "r");
  if (!pipe)
    return;

  char path[1024];
  if (fgets(path, sizeof(path), pipe)) {
    path[strcspn(path, "\n")] = '\0';
    strncpy(cfg.file_path, path, sizeof(cfg.file_path) - 1);
    cfg.file_path[sizeof(cfg.file_path) - 1] = '\0';
  }
  pclose(pipe);
}

void run_cli() {
  char cmd[4096] = "./peruere ";
  size_t cmd_len = strlen(cmd);

  if ((strlen(cfg.file_path) == 0 && strlen(cfg.url) == 0) ||
      (strlen(cfg.file_path) > 0 && strlen(cfg.url) > 0)) {
    fprintf(stderr, "Select local file or enter URL (choose one)\n");
    return;
  }

  if (strlen(cfg.file_path) > 0) {
    if (cmd_len + strlen(cfg.file_path) + 10 < sizeof(cmd)) {
      sprintf(cmd + cmd_len, "--file \"%s\" ", cfg.file_path);
      cmd_len = strlen(cmd);
    } else {
      fprintf(stderr, "Command buffer overflow\n");
      return;
    }
  }
  if (strlen(cfg.url) > 0) {
    if (cmd_len + strlen(cfg.url) + 10 < sizeof(cmd)) {
      sprintf(cmd + cmd_len, "--url \"%s\" ", cfg.url);
      cmd_len = strlen(cmd);
    } else {
      fprintf(stderr, "Command buffer overflow\n");
      return;
    }
  }
  if (cmd_len + strlen(cfg.geometry) + 10 < sizeof(cmd)) {
    sprintf(cmd + cmd_len, "--geometry %s ", cfg.geometry);
    cmd_len = strlen(cmd);
  } else {
    fprintf(stderr, "Command buffer overflow\n");
    return;
  }
  if (cfg.keep_cache) {
    if (cmd_len + 6 < sizeof(cmd)) {
      strcat(cmd, "--keep");
    } else {
      fprintf(stderr, "Command buffer overflow\n");
      return;
    }
  }

  system(cmd);
}

void redraw() {
  XClearWindow(dpy, win);

  draw_text(200, 40, "Video Desktop Player", 0x555555);

  draw_input_box(&input_file);
  draw_input_box(&input_url);
  draw_input_box(&input_geometry);

  draw_button(&btn_browse);
  draw_button(&btn_play);
  draw_button(&btn_clean);
  draw_button(&btn_help);

  draw_rect_border(50, 260, 20, 20, 0x000000);
  if (cfg.keep_cache)
    draw_rect(52, 262, 16, 16, 0x000000);
  draw_text(80, 280, "Keep Cache (-k)", 0x000000);

  if (show_help) {
    draw_rect(50, 50, 500, 300, 0xFFFFFF);
    draw_rect_border(50, 50, 500, 300, 0xFF0000);

    char help_buf[1024];
    strncpy(help_buf, help_text, sizeof(help_buf) - 1);
    help_buf[sizeof(help_buf) - 1] = '\0';

    char *line = strtok(help_buf, "\n");
    int y = 70;
    while (line) {
      draw_text(70, y, line, 0x000000);
      y += 20;
      line = strtok(NULL, "\n");
    }
  }

  XFlush(dpy);
}

int main() {
  dpy = XOpenDisplay(NULL);
  if (!dpy) {
    fprintf(stderr, "Cannot open display\n");
    return 1;
  }

  if (init_freetype() != 0) {
    XCloseDisplay(dpy);
    return 1;
  }

  int screen = DefaultScreen(dpy);
  unsigned long white = WhitePixel(dpy, screen);
  unsigned long black = BlackPixel(dpy, screen);

  win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), 100, 100, 600, 400, 1,
                            black, white);
  XSelectInput(dpy, win,
               ExposureMask | ButtonPressMask | ButtonReleaseMask |
                   PointerMotionMask | KeyPressMask);
  XMapWindow(dpy, win);

  gc = XCreateGC(dpy, win, 0, NULL);
  if (!gc) {
    fprintf(stderr, "Failed to create GC\n");
    return 1;
  }

  init_gui();

  XEvent ev;
  while (1) {
    XNextEvent(dpy, &ev);

    if (ev.type == Expose) {
      redraw();
      continue;
    }
    if (ev.type == KeyPress &&
        ev.xkey.keycode == XKeysymToKeycode(dpy, XK_Escape)) {
      if (show_help)
        show_help = false;
      else
        break;
      redraw();
      continue;
    }

    int x = ev.xbutton.x;
    int y = ev.xbutton.y;

    btn_browse.hovered =
        (x >= btn_browse.x && x <= btn_browse.x + btn_browse.w &&
         y >= btn_browse.y && y <= btn_browse.y + btn_browse.h);
    btn_play.hovered = (x >= btn_play.x && x <= btn_play.x + btn_play.w &&
                        y >= btn_play.y && y <= btn_play.y + btn_play.h);
    btn_clean.hovered = (x >= btn_clean.x && x <= btn_clean.x + btn_clean.w &&
                         y >= btn_clean.y && y <= btn_clean.y + btn_clean.h);
    btn_help.hovered = (x >= btn_help.x && x <= btn_help.x + btn_help.w &&
                        y >= btn_help.y && y <= btn_help.y + btn_help.h);

    if (ev.type == MotionNotify) {
      redraw();
      continue;
    }

    if (ev.type == ButtonPress) {
      input_file.focused =
          (x >= input_file.x && x <= input_file.x + input_file.w &&
           y >= input_file.y && y <= input_file.y + input_file.h);
      input_url.focused = (x >= input_url.x && x <= input_url.x + input_url.w &&
                           y >= input_url.y && y <= input_url.y + input_url.h);
      input_geometry.focused =
          (x >= input_geometry.x && x <= input_geometry.x + input_geometry.w &&
           y >= input_geometry.y && y <= input_geometry.y + input_geometry.h);

      if (btn_browse.hovered) {
        btn_browse.pressed = true;
        open_file_dialog();
      }
      if (btn_play.hovered) {
        btn_play.pressed = true;
        run_cli();
      }
      if (btn_clean.hovered) {
        btn_clean.pressed = true;
        system("./peruere --clean-cache");
      }
      if (btn_help.hovered) {
        btn_help.pressed = true;
        show_help = !show_help;
      }

      if (x >= 50 && x <= 70 && y >= 260 && y <= 280) {
        cfg.keep_cache = !cfg.keep_cache;
      }

      redraw();
      continue;
    }

    if (ev.type == ButtonRelease) {
      btn_browse.pressed = false;
      btn_play.pressed = false;
      btn_clean.pressed = false;
      btn_help.pressed = false;
      redraw();
      continue;
    }

    handle_input(&input_file, &ev);
    handle_input(&input_url, &ev);
    handle_input(&input_geometry, &ev);
    redraw();
  }

  // 严格按顺序释放资源
  FT_Done_Face(ft_face);
  FT_Done_FreeType(ft_lib);
  XFreeGC(dpy, gc);
  XDestroyWindow(dpy, win);
  XCloseDisplay(dpy);

  return 0;
}
